package com.atguigu.mymvc.dao;

import com.alibaba.druid.pool.DruidDataSource;
import com.atguigu.mymvc.util.ClassUtil;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public abstract class BaseDao<T> {

    private String DRIVER ;
    private String URL ;
    private String USER  ;
    private String PWD  ;

    private String entityClassName ;

    public BaseDao(){
        // this是谁？  this代表的是FruitDaoImpl的实例对象
        // this.getClass() 获取的是FruitDaoImpl的Class对象
        // getGenericSuperClass() 获取到的是：   BaseDao<Fruit>
        // Type是顶层接口，表示所有的类型。它有一个子接口：ParameterizedType
        ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        // Actual:实际的
        // getActualTypeArguments() 获取实际的类型参数
        Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
        Type actualTypeArgument = actualTypeArguments[0];
        entityClassName = actualTypeArgument.getTypeName();

        initDataSource();
    }

    private DataSource dataSource ;

    //加载jdbc.properties文件
    private void initDataSource(){
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("jdbc.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            String driver = properties.getProperty("jdbc.driver","com.mysql.cj.jdbc.Driver");
            String url = properties.getProperty("jdbc.url","jdbc:mysql:///fruitdb");
            String user = properties.getProperty("jdbc.user","root");
            String pwd = properties.getProperty("jdbc.pwd","atguigu2023");
            Integer initSize = Integer.parseInt(properties.getProperty("jdbc.init_size","5"));
            Integer maxActive = Integer.parseInt(properties.getProperty("jdbc.max_active","10"));
            Integer maxWait = Integer.parseInt(properties.getProperty("jdbc.max_wait","5000"));

            DruidDataSource druidDataSource = new DruidDataSource( );
            druidDataSource.setDriverClassName(driver);
            druidDataSource.setUrl(url);
            druidDataSource.setUsername(user);
            druidDataSource.setPassword(pwd);
            druidDataSource.setInitialSize(initSize);
            druidDataSource.setMaxActive(maxActive);
            druidDataSource.setMaxWait(maxWait);

            dataSource = druidDataSource ;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Connection getConn() throws SQLException {
        return dataSource.getConnection();
    }

    private void close(Connection conn , PreparedStatement psmt , ResultSet rs){
        try {
            if(rs!=null){
                rs.close();
            }
            if (psmt != null) {
                psmt.close();
            }
            if(conn!=null && !conn.isClosed()){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //执行更新，返回影响行数
    //如果是执行insert，那么可以尝试返回自增列的值
    protected int executeUpdate(String sql , Object... params){
        boolean insertFlag = sql.trim().toUpperCase().startsWith("INSERT") ;
        Connection conn = null ;
        PreparedStatement psmt =  null ;
        try{
            conn = getConn() ;
            psmt = insertFlag ? conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
            setParams(psmt,params);
            int count = psmt.executeUpdate();

            if(insertFlag){
                ResultSet rs = psmt.getGeneratedKeys();
                if(rs.next()){
                    Long id = rs.getLong(1);
                    count = id.intValue() ;
                }
            }

            return count ;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(conn,psmt,null);
        }
        return 0 ;
    }

    //设置参数
    private void setParams(PreparedStatement psmt , Object... params) throws SQLException {
        if(params!=null && params.length>0){
            for(int i = 0 ; i<params.length ; i++){
                psmt.setObject(i+1,params[i]);
            }
        }
    }

    //执行查询，返回集合
    protected List<T> executeQuery(String sql , Object... params){
        List<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement psmt = null ;
        ResultSet rs = null ;

        try {
            conn = getConn();
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            ResultSetMetaData rsmd = rs.getMetaData(); //MetaData:元数据 , 结果集的结构数据

            while(rs.next()){
                //T t = new T();
                T t = (T)ClassUtil.createInstance(entityClassName);
                int columnCount = rsmd.getColumnCount(); //获取结果集的列的数量
                for(int i = 1 ; i<=columnCount ; i++){
                    //假设循环5次，得到5个值，应该对应的是一个对象的5个属性的值
                    String columnName = rsmd.getColumnLabel(i);
                    Object columnValue = rs.getObject(i);
                    //给t这个对象的columnName属性赋columnValue值
                    ClassUtil.setProperty(t,columnName,columnValue);
                }
                list.add(t);
            }
            return list ;
        } catch ( SQLException e) {
            e.printStackTrace();
        } finally {
            close(conn,psmt,rs);
        }
        return list ;
    }

    protected T load(String sql , Object... params){
        Connection conn = null;
        PreparedStatement psmt = null ;
        ResultSet rs = null ;

        try {
            conn = getConn();
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            ResultSetMetaData rsmd = rs.getMetaData(); //MetaData:元数据 , 结果集的结构数据

            if(rs.next()){
                //T t = new T();
                T t = (T)ClassUtil.createInstance(entityClassName);
                int columnCount = rsmd.getColumnCount(); //获取结果集的列的数量
                for(int i = 1 ; i<=columnCount ; i++){
                    //假设循环5次，得到5个值，应该对应的是一个对象的5个属性的值
                    String columnName = rsmd.getColumnLabel(i);
                    Object columnValue = rs.getObject(i);
                    //给t这个对象的columnName属性赋columnValue值
                    ClassUtil.setProperty(t,columnName,columnValue);
                }
                return t ;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(conn,psmt,rs);
        }
        return null ;
    }

    // select max(age) as max_age , avg(age) as avg_age from t_user
    //    28     24.5

    // select deptNo,avg(sal) as avg_sal   from emp group by deptNo
    /*
       d001       3500
       d002       3650
       d003       2998
     */
    protected List<Object[]> executeComplexQuery(String sql , Object... params){
        List<Object[]> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement psmt = null ;
        ResultSet rs = null ;

        try {
            conn = getConn();
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            ResultSetMetaData rsmd = rs.getMetaData(); //MetaData:元数据 , 结果集的结构数据

            while(rs.next()){
                int columnCount = rsmd.getColumnCount(); //获取结果集的列的数量
                Object[] arr = new Object[columnCount];
                for(int i = 1 ; i<=columnCount ; i++){
                    Object columnValue = rs.getObject(i);
                    arr[i-1]=columnValue;
                }
                list.add(arr);
            }
            return list ;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(conn,psmt,rs);
        }
        return null ;
    }


}
